Crate tiny_pretty

source ·
Expand description

Tiny implementation of Wadler-style pretty printing algorithm.

§Basic Usage

Supposed we’re going to print a code snippet of function calls, and we already have data structure defined as:

struct FunctionCall {
    name: String,
    args: Vec<FunctionCall>,
}

We may have a function call that is very very long, so we need to pretty print it for better readability. Our function call may behave like:

let fn_call = FunctionCall {
    name: "foo".into(),
    args: vec![
        FunctionCall { name: "really_long_arg".into(), args: vec![] },
        FunctionCall { name: "omg_so_many_parameters".into(), args: vec![] },
        FunctionCall { name: "we_should_refactor_this".into(), args: vec![] },
        FunctionCall { name: "is_there_seriously_another_one".into(), args: vec![] },
    ],
};

(This example is copied from Prettier with modifications.)

Now we’re going to implement about building Doc from the data structure above. We expect arguments should be placed on a single line as possible. If they’re too long to fit, we insert line break with indentation:

  • When being on a single line, there’re no spaces after left paren and before right paren, and there must be a space after each argument comma.
  • When being splitted into different lines, there must be indentation when printing arguments, and there must be a line break between arguments.

So, we can build Doc like this:

use itertools::Itertools;
use tiny_pretty::Doc;

fn build_doc(fn_call: &FunctionCall) -> Doc {
    Doc::text(&fn_call.name)
        .append(Doc::text("("))
        .append(
            Doc::line_or_nil()
                .append(Doc::list(Itertools::intersperse(
                    fn_call.args.iter().map(build_doc),
                    Doc::text(",").append(Doc::line_or_space())
                ).collect()))
                .nest(2)
                .append(Doc::line_or_nil())
                .group()
        )
        .append(Doc::text(")"))
}

Once we have a Doc, we can pretty print it:

use tiny_pretty::{print, PrintOptions};

assert_eq!(r#"
foo(
  really_long_arg(),
  omg_so_many_parameters(),
  we_should_refactor_this(),
  is_there_seriously_another_one()
)"#.trim(), &print(&build_doc(&fn_call), &PrintOptions::default()));

Besides, if we have a function call which is short enough to fit on single line:

use tiny_pretty::{print, PrintOptions};

let fn_call = FunctionCall {
    name: "foo".into(),
    args: vec![
        FunctionCall { name: "a".into(), args: vec![] },
        FunctionCall { name: "b".into(), args: vec![] },
        FunctionCall { name: "c".into(), args: vec![] },
        FunctionCall { name: "d".into(), args: vec![] },
    ],
};

assert_eq!(
    "foo(a(), b(), c(), d())",
    &print(&build_doc(&fn_call), &PrintOptions::default()),
);

You can specify advanced printing options, such as controlling line break and indentation kind. See PrintOptions for details.

§Text Width Measurement

By default, text width is measured as “visual width”. This strategy makes it satisfy the width limitation visually.

But sometimes for some Unicode characters, you may want the column to be close to width limitation as possible, though it will exceed visually. To achieve that, please enable the unicode-width feature gate.

Structs§

  • Print control options, such as line break and indentation kind.

Enums§

Functions§